#include "../header/sharemem.h"

// --- 本地内存模拟实现（当系统不支持共享内存时） ---
typedef struct {
    key_t key;
    shm_string shm;
    int used;
} local_shm_slot;

#define LOCAL_SHM_MAX 8
static local_shm_slot local_shm_table[LOCAL_SHM_MAX] = {0};

static local_shm_slot* find_local_slot(key_t key, int create) {
    int i;
    for (i = 0; i < LOCAL_SHM_MAX; ++i) {
        if (local_shm_table[i].used && local_shm_table[i].key == key) {
            return &local_shm_table[i];
        }
    }
    if (create) {
        for (i = 0; i < LOCAL_SHM_MAX; ++i) {
            if (!local_shm_table[i].used) {
                local_shm_table[i].used = 1;
                local_shm_table[i].key = key;
                memset(&local_shm_table[i].shm, 0, sizeof(shm_string));
                return &local_shm_table[i];
            }
        }
    }
    return NULL;
}

static int shm_system_supported = -1; // -1: 未检测, 0: 不支持, 1: 支持

static void check_shm_support() {
    if (shm_system_supported != -1) return;
    key_t test_key = 0x7fff0000;
    int shmid = shmget(test_key, 64, IPC_CREAT | 0666);
    if (shmid < 0) {
        shm_system_supported = 0;
    } else {
        shmctl(shmid, IPC_RMID, NULL);
        shm_system_supported = 1;
    }
}

// 创建或获取共享内存，返回共享内存指针，失败返回NULL
shm_string* shm_string_attach(key_t key, int *shmid_out) {
    check_shm_support();
    if (shm_system_supported == 1) {
        int shmid = shmget(key, SHM_SIZE, IPC_CREAT | 0666);
        if (shmid < 0) {
            //perror("shmget failed");
            return NULL;
        }
        if (shmid_out) *shmid_out = shmid;
        void *shmaddr = shmat(shmid, NULL, 0);
        if (shmaddr == (void *)-1) {
            //perror("shmat failed");
            return NULL;
        }
        return (shm_string*)shmaddr;
    } else {
        // 本地模拟
        local_shm_slot *slot = find_local_slot(key, 1);
        if (!slot) return NULL;
        if (shmid_out) *shmid_out = -1;
        return &slot->shm;
    }
}

// 分离共享内存
void shm_string_detach(shm_string *shm) {
    check_shm_support();
    if (shm_system_supported == 1) {
        if (shm) shmdt((void*)shm);
    }
    // 本地模拟无需操作
}

// 删除共享内存
void shm_string_remove(int shmid) {
    check_shm_support();
    if (shm_system_supported == 1) {
        shmctl(shmid, IPC_RMID, NULL);
    } else {
        // 本地模拟: 标记unused
        int i;
        for (i = 0; i < LOCAL_SHM_MAX; ++i) {
            if (local_shm_table[i].used) {
                local_shm_table[i].used = 0;
            }
        }
    }
}

// 写入string到指定key的共享内存，ttl为过期秒数（0表示不过期），返回0成功，-1失败
int shm_string_set_ttl(key_t key, const char *str, time_t ttl_sec) {
    int shmid;
    shm_string *shm = shm_string_attach(key, &shmid);
    if (!shm) return -1;
    // 限制写入数据长度，防止溢出
    size_t max_data_len = sizeof(shm->data) - 1;
    size_t len = strlen(str);
    if (len > max_data_len) len = max_data_len;
    memcpy(shm->data, str, len);
    shm->data[len] = '\0';
    shm->data_len = len;
    if (ttl_sec > 0) {
        shm->expire_at = time(NULL) + ttl_sec;
    } else {
        shm->expire_at = 0; // 0表示不过期
    }
    shm_string_detach(shm);
    return 0;
}

// 写入string到指定key的共享内存，使用默认ttl
int shm_string_set(key_t key, const char *str) {
    return shm_string_set_ttl(key, str, SHM_STRING_TTL_DEFAULT);
}

// 从指定key的共享内存读取string，buf为输出缓冲区，bufsize为缓冲区大小，返回实际长度
// 如果已过期则自动清除并返回0
size_t shm_string_get(key_t key, char *buf, size_t bufsize) {
    int shmid;
    shm_string *shm = shm_string_attach(key, &shmid);
    if (!shm) return 0;
    time_t now = time(NULL);
    size_t len = 0;
    if (shm->expire_at != 0 && now > shm->expire_at) {
        // 已过期，自动清除
        shm_string_detach(shm);
        if (shm_system_supported == 1) {
            shm_string_remove(shmid);
        } else {
            // 本地模拟: 标记unused
            int i;
            for (i = 0; i < LOCAL_SHM_MAX; ++i) {
                if (local_shm_table[i].used && &local_shm_table[i].shm == shm) {
                    local_shm_table[i].used = 0;
                    break;
                }
            }
        }
        return 0;
    }
    // 限制读取长度，防止溢出
    len = shm->data_len;
    if (len >= bufsize) len = bufsize - 1;
    if (len > sizeof(shm->data)) len = sizeof(shm->data) - 1;
    memcpy(buf, shm->data, len);
    buf[len] = '\0';
    shm_string_detach(shm);
    return len;
}

// 获取指定key的剩余ttl（秒），如果不存在或已过期返回0，0表示已过期或永久有效
time_t shm_string_ttl(key_t key) {
    int shmid;
    shm_string *shm = shm_string_attach(key, &shmid);
    if (!shm) return 0;
    time_t now = time(NULL);
    time_t ttl = 0;
    if (shm->expire_at == 0) {
        ttl = 0; // 永久有效
    } else if (now > shm->expire_at) {
        // 已过期，自动清除
        shm_string_detach(shm);
        if (shm_system_supported == 1) {
            shm_string_remove(shmid);
        } else {
            // 本地模拟: 标记unused
            int i;
            for (i = 0; i < LOCAL_SHM_MAX; ++i) {
                if (local_shm_table[i].used && &local_shm_table[i].shm == shm) {
                    local_shm_table[i].used = 0;
                    break;
                }
            }
        }
        return 0;
    } else {
        ttl = shm->expire_at - now;
    }
    shm_string_detach(shm);
    return ttl;
}

// 计算简单的校验和
uint32_t shm_calculate_checksum(const void *data, size_t len) {
    uint32_t checksum = 0;
    const unsigned char *bytes = (const unsigned char *)data;
    for (size_t i = 0; i < len; i++) {
        checksum = (checksum << 1) + bytes[i];
    }
    return checksum;
}

// 验证校验和
int shm_verify_checksum(const shm_string *shm) {
    if (!shm) return 0;
    uint32_t calculated = shm_calculate_checksum(shm->data, shm->data_len);
    return (calculated == shm->checksum);
}

// 写入二进制数据到共享内存
int shm_string_set_binary(key_t key, const void *data, size_t data_len, time_t ttl_sec) {
    int shmid;
    shm_string *shm = shm_string_attach(key, &shmid);
    if (!shm) return -1;
    
    if (data_len > SHM_MAX_DATA_SIZE) {
        shm_string_detach(shm);
        return -1; // 数据太大
    }
    
    memcpy(shm->data, data, data_len);
    shm->data_len = data_len;
    shm->checksum = shm_calculate_checksum(shm->data, data_len);
    
    if (ttl_sec > 0) {
        shm->expire_at = time(NULL) + ttl_sec;
    } else {
        shm->expire_at = 0;
    }
    
    shm_string_detach(shm);
    return 0;
}

// 读取二进制数据
size_t shm_string_get_binary(key_t key, void *buf, size_t bufsize) {
    int shmid;
    shm_string *shm = shm_string_attach(key, &shmid);
    if (!shm) return 0;
    
    time_t now = time(NULL);
    if (shm->expire_at != 0 && now > shm->expire_at) {
        // 已过期，自动清除
        shm_string_detach(shm);
        if (shm_system_supported == 1) {
            shm_string_remove(shmid);
        }
        return 0;
    }
    
    // 验证校验和
    if (!shm_verify_checksum(shm)) {
        shm_string_detach(shm);
        return 0; // 数据损坏
    }
    
    size_t len = shm->data_len;
    if (len > bufsize) len = bufsize;
    if (len > SHM_MAX_DATA_SIZE) len = SHM_MAX_DATA_SIZE;
    
    memcpy(buf, shm->data, len);
    shm_string_detach(shm);
    return len;
}

// 获取可用大小
size_t shm_get_available_size(key_t key) {
    int shmid;
    shm_string *shm = shm_string_attach(key, &shmid);
    if (!shm) return 0;
    
    time_t now = time(NULL);
    if (shm->expire_at != 0 && now > shm->expire_at) {
        shm_string_detach(shm);
        if (shm_system_supported == 1) {
            shm_string_remove(shmid);
        }
        return 0;
    }
    
    size_t available = SHM_MAX_DATA_SIZE - shm->data_len;
    shm_string_detach(shm);
    return available;
}